/**
 * 报表设计公司(2011)
 */
package com.reportgear.report.print;

import java.awt.print.PageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.swing.JOptionPane;

import net.abbp.report.model.ReportModel;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.abbp.core.utils.UnitUtils;
import com.reportgear.report.model.auxiliary.ColumnPropList;
import com.reportgear.report.model.auxiliary.RowPropList;
import com.reportgear.report.setting.PaperSetting;
import com.reportgear.report.setting.ReportSettings;

/**
 * 报表页面生成迭代器
 * 
 * @version 1.0 2011-3-23
 * @author <a herf="lexloo@gmail.com">lexloo</a>
 * @since ANNCSR 2.0
 */
public class ReportPageIterator implements Iterator<ReportPage> {
	private static final Logger logger = LoggerFactory.getLogger(ReportPageIterator.class.getName());
	// 分页列索引
	private final List<Integer> pageColumnIndexList = new ArrayList<Integer>();
	// 分页行索引
	private final List<Integer> pageRowIndexList = new ArrayList<Integer>();
	// 总页数
	private int pageCount = 0;
	// 页面列表
	private LinkedList<ReportPage> pageList = new LinkedList<ReportPage>();

	private FT detailColumns;
	private FT detailRows;

	private Thread pageGenerateThread;

	// 处理的报表模型
	private ReportModel model;

	/**
	 * 构造函数
	 * 
	 * @param report
	 *            报表对象
	 */
	public ReportPageIterator(ReportModel report) {
		this.model = report;

		dealWithPageInfo();
	}

	/**
	 * 分组页信息
	 */
	private static class GroupPageInfo {
		// 分组页码
		private int pageNumber;
		// 总页数(默认-1，不存在，由程序改写)
		private int totalPages = -1;

		private GroupPageInfo(int pageNumber) {
			this.pageNumber = pageNumber;
		}
	}

	/**
	 * 页面生成线程
	 */
	private class PageGenerateThread extends Thread {

		private PageGenerateThread() {
		}

		/**
		 * 处理报表页
		 * 
		 * @param rowFT
		 *            行FT
		 * @param columnFT
		 *            列FT
		 * @param pageNum
		 *            页码
		 * @param groupPageNum
		 *            分组页码
		 * @param groupPageCount
		 *            分组总页数
		 */
		private void generateReportPage(FT rowFT, FT columnFT, int pageNum, int groupPageNum, int groupPageCount) {
			ReportPage reportPage = new ReportPage(model, rowFT, columnFT);

			reportPage.setCurrentPageNumber(pageNum);
			reportPage.setTotalPages(pageCount);
			reportPage.setGroupPageNumber(groupPageNum);
			reportPage.setGroupTotalPages(groupPageCount);

			pageList.add(reportPage);
		}

		@Override
		public void run() {
			int pageNum = 1;
			int groupPageNum = 1;
			int groupTotal = 1;

			FT rowFT;
			FT columnFT;

			// 行信息
			RowPropList rpl = model.getRowPropList();
			// 存储分组页信息
			Map<String, GroupPageInfo> groupInfoMap = new HashMap<String, GroupPageInfo>();

			// 计算组分页信息
			for (int i = 0, rsize = pageRowIndexList.size() - 1; i < rsize; i++) {
				// 如果是分组,则行属性必定为分组
				if (rpl.isGroup(pageRowIndexList.get(i))) {
					for (GroupPageInfo gpi : groupInfoMap.values()) {
						if (gpi.totalPages == -1) {
							gpi.totalPages = groupPageNum - 1;
						}
					}
					groupPageNum = 1;
				}

				for (int j = 0, csize = pageColumnIndexList.size() - 1; j < csize; j++) {
					groupInfoMap.put(i + "_" + j, new GroupPageInfo(groupPageNum));

					groupPageNum++;
				}
			}

			for (GroupPageInfo gpi : groupInfoMap.values()) {
				if (gpi.totalPages == -1) {
					gpi.totalPages = groupPageNum;
				}
			}

			for (int i = 0, rsize = pageRowIndexList.size() - 1; i < rsize; i++) {
				rowFT = new FT(pageRowIndexList.get(i), pageRowIndexList.get(i + 1));
				for (int j = 0, csize = pageColumnIndexList.size() - 1; j < csize; j++) {
					columnFT = new FT(pageColumnIndexList.get(j), pageColumnIndexList.get(j + 1));

					GroupPageInfo gpi = groupInfoMap.get(i + "_" + j);
					generateReportPage(rowFT, columnFT, pageNum, gpi.pageNumber, gpi.totalPages);

					pageNum++;
				}
			}
		}
	}

	public boolean hasNext() {
		if (pageGenerateThread == null) {
			pageGenerateThread = new PageGenerateThread();
			pageGenerateThread.setPriority(3);
			pageGenerateThread.start();
		}

		while (true) {
			if (pageList.size() > 0) {
				return true;
			} else {
				try {
					Thread.sleep(500L);
				} catch (final InterruptedException ex) {
					logger.warn(ex.getMessage());
				}
				if (pageList.size() == 0) {
					break;
				}
			}
		}

		return false;
	}

	public ReportPage next() {
		if (pageList.size() == 0) {
			return null;
		}

		return pageList.removeFirst();
	}

	public void remove() {
		throw new UnsupportedOperationException("不可移除");
	}

	public int size() {
		return pageCount;
	}

	/**
	 * 获取页面信息
	 */
	private void dealWithPageInfo() {
		ReportSettings reportSettings = model.getReportSettings();
		PaperSetting paperSetting = reportSettings.getPaperSetting();
		PaperSize pageSize = paperSetting.getPaperSize();
		Margin margin = paperSetting.getMargin();
		double pageWdith = 0;
		double pageHeight = 0;

		if (paperSetting.getOrientation() == PageFormat.LANDSCAPE) {
			pageWdith = Math.max(pageSize.getWidth(), pageSize.getHeight());
			pageHeight = Math.min(pageSize.getWidth(), pageSize.getHeight());
		} else if (paperSetting.getOrientation() == PageFormat.PORTRAIT) {
			pageWdith = Math.min(pageSize.getWidth(), pageSize.getHeight());
			pageHeight = Math.max(pageSize.getWidth(), pageSize.getHeight());
		}

		double temp = (pageWdith - margin.getLeft() - margin.getRight());
		int pagePixelWidth = UnitUtils.inch2pixel(temp);

		temp = pageHeight - margin.getTop() - margin.getBottom() - reportSettings.getHeaderHeight()
				- reportSettings.getFooterHeight();
		int pagePixelHeight = UnitUtils.inch2pixel(temp);

		int columnCount = model.getColumnCount();
		int rowCount = model.getRowCount();

		detailRows = new FT(0, rowCount);
		detailColumns = new FT(0, columnCount);

		this.calcColumnPaging(pagePixelWidth, columnCount);
		this.calcRowPaging(pagePixelHeight, rowCount);

		pageCount = (pageColumnIndexList.size() - 1) * (pageRowIndexList.size() - 1);
	}

	// 计算分页列位置信息
	private void calcColumnPaging(int pagePixelWidth, int columnCount) {
		ColumnPropList columnWidthList = this.model.getColumnPropList();
		pageColumnIndexList.add(0);

		int fixedWidth = this.getFixedWidth();
		int calTotalWidth = fixedWidth;

		// TODO 一列都不能打完的时候会出现错误
		if (calTotalWidth > pagePixelWidth) {
			JOptionPane.showMessageDialog(null, "固定列宽大于纸张宽度，不能预览与打印", "警告", JOptionPane.WARNING_MESSAGE);
			return;
		}
		int calWidth = 0;
		for (int c = detailColumns.getFrom(); c < detailColumns.getTo(); c++) {
			if (this.model.isFixedColumn(c)) {
				continue;
			}

			calTotalWidth += (calWidth = columnWidthList.getWidth(c));

			if (calTotalWidth <= pagePixelWidth && !columnWidthList.isGroup(c)) {
				continue;
			}

			pageColumnIndexList.add(c);
			calTotalWidth = fixedWidth + calWidth;
		}

		pageColumnIndexList.add(columnCount);
	}

	/**
	 * 返回固定列宽度
	 * 
	 * @return 宽度
	 */
	private int getFixedWidth() {
		int result = 0;
		ColumnPropList columnWidthList = this.model.getColumnPropList();

		for (int i : this.model.getFixedHeaderColumns()) {
			result += columnWidthList.getWidth(i);
		}

		for (int i : this.model.getFixedFooterColumns()) {
			result += columnWidthList.getWidth(i);
		}

		return result;
	}

	// 计算分页行位置
	private void calcRowPaging(int pagePixelHeight, int rowCount) {
		RowPropList rowHeightList = this.model.getRowPropList();
		pageRowIndexList.add(0);

		int fixedHeight = this.getFixedHeight();
		int calTotalHeight = fixedHeight;

		int calHeight = 0;

		for (int r = detailRows.getFrom(); r < detailRows.getTo(); r++) {
			if (this.model.isFixedRow(r)) {
				continue;
			}

			calTotalHeight += (calHeight = rowHeightList.getHeight(r));

			if (!rowHeightList.isGroup(r) && calTotalHeight <= pagePixelHeight) {
				continue;
			}

			pageRowIndexList.add(r);
			calTotalHeight = fixedHeight + calHeight;
		}
		pageRowIndexList.add(rowCount);
	}

	/**
	 * 返回固定行高度
	 * 
	 * @return 高度
	 */
	private int getFixedHeight() {
		int result = 0;

		RowPropList rhL = this.model.getRowPropList();

		for (int i : this.model.getFixedHeaderRows()) {
			result += rhL.getHeight(i);
		}

		for (int i : this.model.getFixedFooterRows()) {
			result += rhL.getHeight(i);
		}

		return result;
	}
}